#encoding=utf8
import re

java_type_mapping = {
  "int" : "Integer",
  "long" : "Long",
  "float" : "Float",
  "double" : "Double",
  "boolean" : "Boolean",
  "byte" : "Byte"
}

class Parameter:
  def __init__(self, type, name, optional = False):
    self.type = type
    self.name = name
    self.optional = optional

class Method:
  def __init__(self, name):
    self.name = name
    self.paramters = []
    self.comment = ""
  
  def addParameter(self, type, name, optional = False):
    self.paramters.append(Parameter(type, name, optional))

class Service:
  def __init__(self, name):
    self.name = name
    self.methods = []
    self.comment = ""
  
  def addMethod(self, method):
    self.methods.append(method)

def find(content, regex):
  parts = re.findall(regex, content)
  if len(parts) > 0:
    return parts[0]
  return None

def parseComment(content, index):
  part = content[:index]
  part = part[: part.rfind("\n")]
  end = part.rfind("*/")
  if end >= 0:
    start = part[:end].rfind("/*")
    if not start: start = 0
    else: start = part[:start].rfind("\n") + 1
    if part[end + 2:].strip() == "":
      return "\n" + part[start:end + 2]
  return ""

def parseAttributes(content):
  parts = content.split(",")
  result = {}
  for p in parts:
    i = p.find("=")
    if i <= 0:
      k = ""
      v = p.strip()
    else:
      k = p[:i].strip()
      v = p[i + 1:].strip()
    if v == "": continue
    if v[0] == '"': v = v[1:]
    if v[-1] == '"': v = v[:-1]
    result[k] = v
  return result

def parse(src):
  """ 解析java源文件 """
  fin = open(src, "r")
  content = fin.read()
  fin.close()

  try:
    content = content.decode("gbk").encode("utf8")
  except: pass
    

  content = content.replace("\r", "")
  while content.find("\n\n") >= 0:
    content = content.replace("\n\n", "\n")
  
  index = 0
  re_name_interface = re.compile("(?i)interface\s*([^\s]+)\s*{")
  re_name_service =  re.compile("(?i)@Service\([\s]*\"([^\"]+)\"")

  name = find(content, re_name_service)
  if name == None:
    name = find(content, re_name_interface)
    if name == None:
      print "No name"
      return None
    else:
      index = re_name_interface.search(content).start()
  else:
    index = re_name_service.search(content).start()
  
  service = Service(name)
  service.comment = parseComment(content, index)
 
  re_comment = re.compile("(\/\/[^\n]*)")
  content = re.sub(re_comment, "", content)
  re_method = re.compile("(?i)(@Endpoint[^;]*);")
  re_endpoint = re.compile("(?i)@Endpoint[\s]*\(([^\)]*)\)")

  
  re_other_parameters = re.compile("(?i)(@[^\(]*\([^\)]*)")
  re_repl_endpoint = re.compile("(?i)(@Endpoint)")
  re_repl_param = re.compile("(?i)(@Param)")

  re_method_name = re.compile("[\s]+([^\s\(]+)[\s]*\(")
  re_method_parameter = re.compile("(?i)(@Param\([^\)]+\)[^,]*[,|\)])")
  re_method_parameter_attrs = re.compile("(?i)@Param[\s]*\(([^\)]*)\)")
  #re_method_parameter = re.compile("(?i)([^\s,]*[,|\)])")

  methods = {}
  parts = re.findall(re_method, re.sub(re_comment, "", content))
  for part in parts:
    index = content.find(part)
    comment = parseComment(content, index)
    method_name = None
    endpoints = find(part, re_endpoint)
    if endpoints != None:
      attr = parseAttributes(endpoints)
      if attr.has_key("alias"): method_name = attr["alias"]
      elif attr.has_key(""): method_name = attr[""]
    if method_name == None:
      method_name = find(part, re_method_name)
    if method_name == None: continue

    if methods.has_key(method_name):
      print "Duplicate method name:%s.%s" % (service.name, method_name)
      return None
    methods[method_name] = 1

    method = Method(method_name)
    method.comment = comment

    if endpoints != None:
      part = part[part.find(")") + 1:]
    part = part[part.find("(") + 1:].strip()

    if not part.endswith(")"):
      part = part[: part.rfind(")") + 1]
  
    service.addMethod(method)
    if part == "": continue

    part = re.sub(re_repl_endpoint, "$endpoint", part)
    part = re.sub(re_repl_param, "$param", part)
    part = re.sub(re_other_parameters, "", part).replace("$param", "@Param").replace("$endpoint", "@Endpoint")

    # split parameters
    start = 0
    end = part.find(",")
    temp = part.find(")")
    if end < temp: end = part.find(",", temp)
    if end < start: end = len(part)

    while end > start + 2:
      parameter_name = None
      parameter_optional = False
      p = part[start: end].strip()


      ps = p.split(" ")
      parameter_type = ps[-2]
      index = parameter_type.rfind(")")
      if index >= 0: parameter_type = parameter_type[index + 1:]


      attrs = find(p, re_method_parameter_attrs)
      if attrs != None:
        attrs = parseAttributes(attrs)
	if attrs.has_key("value"): parameter_name = attrs["value"]
	elif  attrs.has_key(""): parameter_name = attrs[""]
	if attrs.has_key("optional"): parameter_optional = attrs["optional"] == "true"


      if parameter_name == None:
        parameter_name = p[p.rfind(" ") + 1:]
      method.addParameter(parameter_type, parameter_name, parameter_optional)

      start = end + 1
      if start >= len(part): break
      end = part.find(",", start)
      temp = part.find(")", start)
      if end < temp: end = part.find(",", temp)
      if end < start: end = len(part)
  return service


def generateJava(service):
  has_map = False
  for method in service.methods:
    for p in method.paramters:
      if p.optional:
        has_map = True
	break
    if has_map: break
  
  import_map = "\n"
  if has_map: import_map = "import java.util.HashMap;\n"

  name = service.name
  #if name.endswith("Service"): name = name[:-len("Service")]
  name += "Client"

  fout = open("javaclient/%s.java" % name, "w")
  print "Generate: javaclient/%s.java" % name

  print >> fout, """package com.sdna.unified;

import java.io.UnsupportedEncodingException;

import com.sdna.rpc.RPCClientMgr;
import com.sdna.rpc.RPCClient;
import com.sdna.rpc.ParameterBuilder;
%s
%s

/**
  * This file is generated by GenerateServiceClient.py, SVN location:
  *     svn://192.168.90.69/i.sdo.com/sdk/trunk/unified/GenerateServiceClient.py
  *
  * Please DO NOT change this file!!! it is just a wrapper of unified service api.   
  */

public class %s {""" % (import_map, service.comment, name)

  for method in service.methods:

    fout.write("%s\n\tstatic public String %s(" % (method.comment, method.name))
    has_optional = False
    params = ""
    for p in method.paramters:
      if not p.optional: continue
      has_optional = True
      if params == "":
        params += "\"%s\"" % p.name
      else:
        params += ", \"%s\"" % p.name
    started = False
    for p in method.paramters:
      if p.optional: continue
      if not started: started = True
      else:  fout.write(", ")
	
      fout.write("%s %s" % (p.type, p.name))
    
    if has_optional:
      if not started: started = True
      else:  fout.write(", ")	
      fout.write("HashMap<String, Object> parameters")
    
    fout.write(") throws UnsupportedEncodingException{\n")
    """if params != "":
      fout.write("\t\t//允许传的参数\n\t\tString[] allowKeys = {%s};\n" % params)
      fout.write("\t\tif (!checkParameter(allowKeys, parameters)) return false;\n")
    """
    if len(method.paramters) == 0:

      fout.write("\t\tRPCClient client = RPCClientMgr.getClient();\n")
      fout.write("\t\ttry {\n")
      fout.write("\t\t\treturn client.doRequest(\"%s.%s\", null);\n" % (service.name, method.name))
      fout.write("\t\t} catch (Exception e) {\n")
      fout.write("\t\t\te.printStackTrace();\n")
      fout.write("\t\t\treturn null;\n")
      fout.write("\t\t} finally {\n")
      fout.write("\t\t\tRPCClientMgr.restore(client);\n")
      fout.write("\t\t}\n")
    else:
      fout.write("\t\tParameterBuilder pb = new ParameterBuilder();\n")
      for p in method.paramters:
        if not p.optional:
	  fout.write("\t\tpb.add(\"%s\", %s);\n" % (p.name, p.name))
	  continue;
        else:
	  type = p.type
	  if java_type_mapping.has_key(p.type): type =  java_type_mapping[p.type]
          fout.write("\t\tif (parameters.containsKey(\"%s\")) pb.add(\"%s\", (%s)parameters.get(\"%s\"));\n" % (p.name, p.name, type, p.name))

      fout.write("\t\tRPCClient client = RPCClientMgr.getClient();\n")
      fout.write("\t\ttry {\n")
      fout.write("\t\t\treturn client.doRequest(\"%s.%s\", pb.toString());\n" % (service.name, method.name))
      fout.write("\t\t} catch (Exception e) {\n")
      fout.write("\t\t\te.printStackTrace();\n")
      fout.write("\t\t\treturn null;\n")
      fout.write("\t\t} finally {\n")
      fout.write("\t\t\tRPCClientMgr.restore(client);\n")
      fout.write("\t\t}\n")
    fout.write("\t}\n")



  fout.write("}")
  fout.close()


def generatePHP(service):

  fout = open("SDOApi%s.php" % service.name, "w")
  print "Generate: SDOApi%s.php" % service.name

  print >> fout, """<?php
include_once(dirname(__FILE__).'/SDOSocket.php');
include_once(dirname(__FILE__).'/SDOApiHelper.php');
%s

/**
  * This file is generated by GenerateServiceClient.py, SVN location:
  *     svn://192.168.90.69/i.sdo.com/sdk/trunk/unified/GenerateServiceClient.py
  *
  * Please DO NOT change this file!!! it is just a wrapper of unified service api.   
  */
class SDOApi%s {""" % (service.comment, service.name)

  for method in service.methods:

    fout.write("%s\n\tstatic public function %s(" % (method.comment, method.name))
    has_optional = False
    params = ""
    for p in method.paramters:
      if not p.optional: continue
      has_optional = True
      if params == "":
        params += "\"%s\"" % p.name
      else:
        params += ", \"%s\"" % p.name
    started = False
    for p in method.paramters:
      if p.optional: continue
      if not started: started = True
      else:  fout.write(", ")
	
      fout.write("$%s" % p.name)
    
    if has_optional:
      if not started: started = True
      else:  fout.write(", ")	
      fout.write("$paramArray = array()")
    
    fout.write(")\n\t{\n")
    if params != "":
      fout.write("\t\t//允许传的参数\n\t\t$allow_param = array(%s);\n" % params)
      fout.write("\t\t$api_param = SDOApiHelper::getAllowArray($allow_param,$paramArray);\n")
    else:
      fout.write("\t\t$api_param = array();\n");

    
    for p in method.paramters:
      if p.optional: continue
      fout.write("\t\t$api_param['%s'] = $%s;\n" % (p.name, p.name))
    
    fout.write("\t\t$api_name = '%s.%s';\n" % (service.name, method.name))
    fout.write("\t\treturn SDOSocket::send($api_name, $api_param);\n")
    fout.write("\t}\n")

  fout.write("}")
  fout.close()

def generateAll(path):
  if os.path.isfile(path):
    service = parse(path)
    if service:
      generatePHP(service)
      generateJava(service)
  elif os.path.isdir(path):
    for f in os.listdir(path):
      if f.endswith(".java"):
        service = parse(path + "/" + f)
        if service:
	  generatePHP(service)
          generateJava(service)
        else: print "Bad java file"

if __name__ == "__main__":
  import sys
  import os
  if len(sys.argv) == 1:
    generateAll("interfaces")
  else:
    generateAll(sys.argv[1])